package com.joonhat.MonkeyFlash;


import net.rim.device.api.applicationcontrol.ApplicationPermissions;
import net.rim.device.api.applicationcontrol.ApplicationPermissionsManager;
import net.rim.device.api.system.ApplicationDescriptor;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Characters;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Keypad;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.Screen;
import net.rim.device.api.ui.TouchEvent;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.UiEngine;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.EditField;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.ObjectChoiceField;
import net.rim.device.api.ui.container.FullScreen;
import net.rim.device.api.ui.decor.BackgroundFactory;

import com.joonhat.MonkeyFlash.BrightScreenChoiceField.FontColor;
import com.joonhat.MonkeyFlash.MyScreen.MyManager;
import com.joonhat.MonkeyFlash.hotkey.Hotkey;

interface SimpleInterface {
	void pushSimpleMode();

	void flashOnWithAdd();

	void flashOffWithDelete();
}

interface DanceInterface {
	void pushDanceFlash();

	void startBusterFlash();

	void flashOn();

	void flashOff();

	void addPermissions();
}

public class MyApp extends UiApplication {

	private static final boolean AFTER_EXIT = true;
	private static Option option = Option.getIns();
	private FlashHandler handler = FlashHandler.getIns();
	private MyScreen mys = new MyScreen();
	private ScreenCtrl screenCtrl;
	
	private static void setHotkeyInStartup() {
		Hotkey.setHotkeyInStatup(option.getHotkey(), 
				ApplicationDescriptor.currentApplicationDescriptor(), AFTER_EXIT);
	}
	
	public MyApp() {
		setHotkeyInStartup();
		setPermissions(new int[] {
				ApplicationPermissions.PERMISSION_INPUT_SIMULATION,
				ApplicationPermissions.PERMISSION_RECORDING });
		addKeyListener(handler);

		screenCtrl = ScreenCtrl.getIns();
		screenCtrl.setScreen(mys);
		pushMyScreen();
	}

	public void pushMyScreen() {
		screenCtrl.pushMyScreen(false);
	}

	public void popMyScreen() {
		screenCtrl.popMyScreen(false);
	}

	public boolean isMyScreenDisplayed() {
		return screenCtrl.isMyScreenDisplayed();
	}

	protected boolean acceptsForeground() {
		// acceptsForeground()가 실행되는 상황들
		// 1. 아이콘을 실행했을때
		// 2. 곰발바닥을 길게 눌러서 switch메뉴가 뜰때
		// 3. end버튼을 눌렀을때
		if (checkNoPushScreen())
			return false;
		pushMyScreen();
		return false;
	}

	private boolean checkNoPushScreen() {
		// end 버튼을 누르면 이유는 모르겠지만
		// isEventThread() == false의 결과가 나온다
		// 그때는 pushScreen을 하면 안되므로
		return isEventThread() == false;
	}

//	public boolean shouldAppearInApplicationSwitcher() {
//		return false;
//	}

	public static void setPermissions(int[] permissions) {
		ApplicationPermissionsManager appPermissionsManager = ApplicationPermissionsManager
				.getInstance();
		ApplicationPermissions appPermission = new ApplicationPermissions();
		for (int i = 0; i < permissions.length; i++) {
			if (appPermissionsManager.getApplicationPermissions()
					.getPermission(permissions[i]) != ApplicationPermissions.VALUE_ALLOW) {
				appPermission.addPermission(permissions[i]);
			}
		}
		appPermissionsManager.invokePermissionsRequest(appPermission);
	}

}

class ScreenCtrl{

	private static ScreenCtrl screenCtrl = new ScreenCtrl();
	private static UiEngine uiEngine = UiApplication.getUiApplication();
	private static Screen screen;
	
	private ScreenCtrl() {}
	
	public static ScreenCtrl getIns(){
		return screenCtrl;
	}
	
	public void setScreen(Screen screen){
		ScreenCtrl.screen = screen;
	}
	
	public synchronized void pushMyScreen(boolean simplePush){
		if (screen == null || screen.isDisplayed()) return;
		uiEngine.pushGlobalScreen(screen, 0, UiApplication.GLOBAL_SHOW_LOWER);
		if (simplePush) return;
		ModeChangeHandler.prepareLastMode();
	}
	
	public synchronized void popMyScreen(boolean simplePop){
		if (screen.isDisplayed() == false) return;
		uiEngine.popScreen(screen);
		if (simplePop) return;
		ModeChangeHandler.closeCurrentMode();
	}
	
	public boolean isMyScreenDisplayed() {
		if (screen == null) return false;
		return screen.isDisplayed();
	}
}

class MyScreen extends FullScreen {

	MyScreen() {
		super(MyManager.getIns(), 0);
	}

	protected boolean touchEvent(TouchEvent message) {

		switch (message.getEvent()) {
		case TouchEvent.MOVE: {
		}
		}

		return super.touchEvent(message);
	}

	protected void sublayout(int width, int height) {
		super.sublayout(width, height);
		setExtent(Display.getWidth(), Display.getHeight()-1);
	}
	
	protected boolean navigationMovement(int dx, int dy, int status, int time) {
		return super.navigationMovement(dx, dy, status, time);
	}

	static class MyManager extends Manager implements FieldChangeListener { 
		
		private static MyManager manager = new MyManager();
		private Option option = Option.getIns();
		private SimpleOption simpleOption = SimpleOption.getIns();

		private EditField blinkOnTime;
		private EditField blinkOffTime;

		private DurationChoiceField durationChoiceField = new DurationChoiceField();
		private BrightScreenChoiceField brightScreenChoiceField = new BrightScreenChoiceField(
				"화면밝기 : ", new String[] { "환하게", "어둡게" }, this);
		private MyChoiceField startupFlashChoiceField = new MyChoiceField(
				"어플 시작시 플래시를", new String[] { "켠다", "끈다" });
		private MyChoiceField ledChoiceField = new MyChoiceField("Led : ",
				new String[] { "켠다", "끈다" });
		private TempEditField hotkeyChoiceField = new TempEditField("단축키",
				"", 1, 0);
//		private MyChoiceField hotkeyChoiceField = new MyChoiceField("",
//				(getAlphabetList()));

		private RemainingTimeField remainingTimeLabel = new RemainingTimeField();
		private FlashOnOffField onOffLabel = new FlashOnOffField();
		
		private FlashOnOffButton onOffButton = new FlashOnOffButton();

		private MyManager() {
			super(0);

			blinkOnTime = new EditField("blinkOnTime = ", "", 100,
					EditField.FILTER_NUMERIC);
			blinkOffTime = new EditField("blinkOffTime = ", "", 100,
					EditField.FILTER_NUMERIC);
			
			add(durationChoiceField);
			add(remainingTimeLabel);
			add(blinkOnTime);
			add(blinkOffTime);
			add(brightScreenChoiceField);
			add(ledChoiceField);
			add(startupFlashChoiceField);
			add(onOffLabel);
			add(onOffButton);
			add(hotkeyChoiceField);
			
			durationChoiceField.setChangeListener(this);
			blinkOnTime.setChangeListener(this);
			blinkOffTime.setChangeListener(this);
			brightScreenChoiceField.setChangeListener(this);
			ledChoiceField.setChangeListener(this);
			startupFlashChoiceField.setChangeListener(this);
			onOffButton.setChangeListener(this);
			hotkeyChoiceField.setChangeListener(this);

			loadOption();
		}
		
		private void loadOption(){
			synchronized (UiApplication.getEventLock()) {
				blinkOnTime.setLabel(String.valueOf(option.getBlinkOnTime())
						+ " : ");
				blinkOffTime.setLabel(String.valueOf(option.getBlinkOffTime())
						+ " : ");
				ledChoiceField.setSelectedIndex((isLed()) 
						? Constant.INDEX_TRUE : Constant.INDEX_FALSE);
				startupFlashChoiceField.setSelectedIndex((isStartupFlashOn()) 
						? Constant.INDEX_TRUE : Constant.INDEX_FALSE);
				
				if (option.getHotkey() != 0){
					hotkeyChoiceField.setText(String.valueOf(option.getHotkey()));
				} else {
					hotkeyChoiceField.setText("");
				}
//				hotkeyChoiceField.setSelectedIndex(option.getHotkey());
			}
		}
		
		public static MyManager getIns() {
			return manager;
		}

		public void setManagerPosition(int x, int y){
			setPosition(x, y);
		}
		
		protected void sublayout(int width, int height) {
			setPosition(AniEffect.getInt(), 0);
			setExtent(Constant.MANAGER_WIDTH, Constant.MANAGER_HEIGHT);

			setPositionChild(durationChoiceField, 10, 10);
			layoutChild(durationChoiceField, width,
					durationChoiceField.getPreferredHeight());

			setPositionChild(remainingTimeLabel, 10, durationChoiceField.getTop()
					+ durationChoiceField.getHeight());
			layoutChild(remainingTimeLabel, remainingTimeLabel.getPreferredWidth(),
					remainingTimeLabel.getPreferredHeight());
			
			setPositionChild(brightScreenChoiceField, 10, remainingTimeLabel.getTop()
					+ remainingTimeLabel.getHeight());
			layoutChild(brightScreenChoiceField, width,
					brightScreenChoiceField.getPreferredHeight());
			
			setPositionChild(ledChoiceField, 10, brightScreenChoiceField.getTop()
					+ brightScreenChoiceField.getHeight());
			layoutChild(ledChoiceField, width,
					ledChoiceField.getPreferredHeight());
			
			setPositionChild(startupFlashChoiceField, 10, ledChoiceField.getTop()
					+ ledChoiceField.getHeight());
			layoutChild(startupFlashChoiceField, width,
					startupFlashChoiceField.getPreferredHeight());

			setPositionChild(onOffLabel, 10, startupFlashChoiceField.getTop()
					+ startupFlashChoiceField.getHeight());
			layoutChild(onOffLabel, width,
					onOffLabel.getPreferredHeight());

			setPositionChild(onOffButton, 10, onOffLabel.getTop()
					+ onOffLabel.getHeight());
			layoutChild(onOffButton, onOffButton.getPreferredWidth(),
					onOffButton.getPreferredHeight());
		
			setPositionChild(hotkeyChoiceField, width/2, onOffLabel.getTop()
					+ onOffLabel.getHeight());
			layoutChild(hotkeyChoiceField, width/2,
					hotkeyChoiceField.getPreferredHeight());
			
			setPositionChild(blinkOnTime, Display.getWidth() + 10, 10);
			layoutChild(blinkOnTime, blinkOnTime.getPreferredWidth(),
					blinkOnTime.getPreferredHeight());

			setPositionChild(blinkOffTime, Display.getWidth() + 10,
					blinkOnTime.getTop() + blinkOnTime.getHeight());
			layoutChild(blinkOffTime, blinkOffTime.getPreferredWidth(),
					blinkOffTime.getPreferredHeight());
		}

		public void fieldChanged(Field field, int i) {
			if (i == PROGRAMMATIC) return;
			if (field == durationChoiceField
					&& i == ObjectChoiceField.CONTEXT_CHANGE_OPTION) {
				DurationChoiceField_FieldChange();
			} else if (field == brightScreenChoiceField) {
				BrightScreenChoiceField_FieldChange();
			} else if (field == blinkOnTime) {
				BlinkOnTime_FieldChange();
			} else if (field == blinkOffTime) {
				BlinkOffTime_FieldChange();
			} else if (field == ledChoiceField) {
				LedChoiceField_FieldChange();
			} else if (field == startupFlashChoiceField) {
				StartupFlashChoiceField_FieldChange();
			} else if (field == onOffButton) {
				OnOffButton_FieldChange();
			} else if (field == hotkeyChoiceField) {
				HotkeyChoiceField_FieldChange();
			}
		}

		private void DurationChoiceField_FieldChange() {
			setDurationCurrentSelect();
		}
		private void BlinkOnTime_FieldChange() {
			setBlinkOnTime(blinkOnTime.getText());
		}
		private void BlinkOffTime_FieldChange() {
			setBlinkOffTime(blinkOffTime.getText());
		}
		private void BrightScreenChoiceField_FieldChange(){
			setBrightScreen((brightScreenChoiceField.getSelectedIndex() == 
					Constant.INDEX_TRUE) ? true : false);
		}
		private void LedChoiceField_FieldChange(){
			setLed((ledChoiceField.getSelectedIndex() == Constant.INDEX_TRUE) 
					? true : false);
		}
		private void StartupFlashChoiceField_FieldChange(){
			setStartupFlashOn((startupFlashChoiceField.getSelectedIndex() == 
					Constant.INDEX_TRUE) ? true : false);
		}
		private void OnOffButton_FieldChange(){
			FlashHandler.getIns().OnOffButton_FieldChange();
		}
		private void HotkeyChoiceField_FieldChange(){
			char selectedHotkey = 0;
			if (hotkeyChoiceField.getText().length() != 0) 
				selectedHotkey = hotkeyChoiceField.getText().charAt(0);
//			String selectedHotkey = (String) hotkeyChoiceField
//					.getChoice(hotkeyChoiceField.getSelectedIndex());
			setHotkey(selectedHotkey);
			System.out.println(" HotkeyChoiceField_FieldChange!!");
			FlashHandler.getIns().HotkeyChoiceField_FieldChange(selectedHotkey);
		}

		public String getDuration() {
			return durationChoiceField.getDuration();
		}
		public void setDurationCurrentSelect() {
			durationChoiceField.setDurationCurrentSelect();
		}

		public String getBlinkOnTime() {
			return option.getBlinkOnTime();
		}
		public void setBlinkOnTime(String time) {
			option.setBlinkOnTime(time);
		}

		public String getBlinkOffTime() {
			return option.getBlinkOffTime();
		}
		public void setBlinkOffTime(String time) {
			option.setBlinkOffTime(time);
		}
		
		public boolean isBrightScreen(){
			return simpleOption.isBrightScreen();
		}
		public void setBrightScreen(boolean isBrightScreen){
			simpleOption.setBrightScreen(isBrightScreen);
		}
		
		private boolean isLed(){
			return simpleOption.isLed();
		}
		private void setLed(boolean isLed){
			simpleOption.setLed(isLed);
		}
		
		private boolean isStartupFlashOn(){
			return simpleOption.isStartupFlashOn();
		}
		private void setStartupFlashOn(boolean isFlashOnStarup){
			simpleOption.setStartupFlashOn(isFlashOnStarup);
		}
		
		public char getHotkey() {
			return option.getHotkey();
		}
		public void setHotkey(char hotkey) {
			this.option.setHotkey(hotkey);
		}
		
		private static String[] getAlphabetList(){
			String[] alphabet = new String[26];
			for (int i = 0; i < alphabet.length; i++){
				alphabet[i] = String.valueOf((char) (i+65));
			}
			return alphabet;
		}
		
		//화면을 pop시키는 기능을 이곳에 넣어야 ChoiceField와의 충돌이 없음
		protected boolean keyDown(int keycode, int time) {
			if (checkCloseKey(Keypad.key(keycode))) {
				ScreenCtrl.getIns().popMyScreen(false);
				return true;
			}	
			return super.keyDown(keycode, time);
		}
		private boolean checkCloseKey(int key) {
			return key == Characters.ESCAPE || key == Keypad.KEY_END;
		}
	}
}


class MyChoiceField extends ObjectChoiceField{
	
	public MyChoiceField(String s, Object[] aobj) {
		super(s, aobj);
	}

	protected void paint(Graphics g) {
		g.setColor(FontColor.getColor());
		super.paint(g);
	}
	
	protected boolean keyDown(int keycode, int time) {
		if (Keypad.key(keycode) == Characters.SPACE)
			return true;
		return super.keyDown(keycode, time);
	}
}

class DurationChoiceField extends MyChoiceField {

	private SimpleOption simpleOption;

	public DurationChoiceField() {
		super("플래쉬 지속시간 : ", new String[] { "1분", "2분", "3분", "5분", "10분",
				"무제한" });
		simpleOption = SimpleOption.getIns();
		setSelectedIndex(getDuration());
	}
	
	public String getDuration() {
		if (Integer.parseInt(simpleOption.getDuration()) == 60000)
			return "1분";
		else if (Integer.parseInt(simpleOption.getDuration()) == 120000)
			return "2분";
		else if (Integer.parseInt(simpleOption.getDuration()) == 180000)
			return "3분";
		else if (Integer.parseInt(simpleOption.getDuration()) == 300000)
			return "5분";
		else if (Integer.parseInt(simpleOption.getDuration()) == 600000)
			return "10분";
		else if (Integer.parseInt(simpleOption.getDuration()) == Integer.MAX_VALUE)
			return "무제한";
		return simpleOption.getDuration();
	}

	public void setDurationCurrentSelect() {
		if (getChoice(getSelectedIndex()).equals("1분")) {
			simpleOption.setDuration(String.valueOf(60000));
		} else if (getChoice(getSelectedIndex()).equals("2분")) {
			simpleOption.setDuration(String.valueOf(120000));
		} else if (getChoice(getSelectedIndex()).equals("3분")) {
			simpleOption.setDuration(String.valueOf(180000));
		} else if (getChoice(getSelectedIndex()).equals("5분")) {
			simpleOption.setDuration(String.valueOf(300000));
		} else if (getChoice(getSelectedIndex()).equals("10분")) {
			simpleOption.setDuration(String.valueOf(600000));
		} else if (getChoice(getSelectedIndex()).equals("무제한")) {
			simpleOption.setDuration(String.valueOf(Integer.MAX_VALUE));
		}
	}
}

class BrightScreenChoiceField extends MyChoiceField implements Observer{

	private static final String RESOURCE_DARK_SIMPLE = "star7.png";
	private static final String RESOURCE_BRIGHT_SIMPLE = "sun7.png";
	private static final String RESOURCE_DANCE = "clupMonkey.png";
	
	private BrightOption brightScreen = BrightOption.getIns();
	private MyManager manager;
	
	private Bitmap brightBitmap;
	private Bitmap darkBitmap;
	
	public BrightScreenChoiceField(String s, Object[] aobj, MyManager manager) {
		super(s, aobj);
		this.manager = manager;
		setBitmapCache();
		brightScreen.addObserver(this);
		update(brightScreen);	
	}

	private void setBitmapCache() {
		brightBitmap = getBitmap(true);
		darkBitmap = getBitmap(false);
	}

	public void update(Observable observable) {
		setSelectedIndex((isBrightScreen()) ? Constant.INDEX_TRUE :
				Constant.INDEX_FALSE);
		setBackground();
	}
	
	private void setBackground(){
		if (brightScreen.isBrightScreen()){
			FontColor.setColor(Color.BLACK);
			setBitmapBackground(brightBitmap);
		} else {
			FontColor.setColor(Color.WHITE);
			setBitmapBackground(darkBitmap);
		}
	}
	
	private Bitmap getBitmap(boolean bright) {
		Bitmap simpleImage = getSimpleImage(bright);
		Bitmap danceImage = getDanceImage();
		Bitmap canvase = new Bitmap(Constant.MANAGER_WIDTH,
				Constant.MANAGER_HEIGHT);
		simpleImage.scaleInto(0, 0, simpleImage.getWidth(), simpleImage.getHeight(), canvase,
				0, 0, Display.getWidth(),
				Display.getHeight(), Bitmap.FILTER_BILINEAR);
		danceImage.scaleInto(0, 0, danceImage.getWidth(), danceImage.getHeight(), canvase,
				Display.getWidth() , 0, Display.getWidth(),
				Display.getHeight(), Bitmap.FILTER_BILINEAR);
		return canvase;
	}

	private Bitmap getDanceImage() {
		return Bitmap.getBitmapResource(RESOURCE_DANCE);
	}
	
	private Bitmap getSimpleImage(boolean bright) {
		if (bright) {
			return Bitmap.getBitmapResource(RESOURCE_BRIGHT_SIMPLE);
		} else {
			return Bitmap.getBitmapResource(RESOURCE_DARK_SIMPLE);
		}
	}
	
	private void setBitmapBackground(Bitmap bitmap) {
		manager.setBackground(BackgroundFactory.createBitmapBackground(bitmap));
	}

	private boolean isBrightScreen(){
		return brightScreen.isBrightScreen();
	}
	
	static class FontColor{
		static int color;
		public static void setColor(int color){
			FontColor.color = color;
		}
		public static int getColor(){
			return color;
		}
	}
}

class AbstractLabelField extends LabelField{
	protected void paint(Graphics g) {
		g.setColor(FontColor.getColor());
		super.paint(g);
	}
}

class RemainingTimeField extends AbstractLabelField implements Observer {
	FlashTimer timer = FlashTimer.getIns();

	public RemainingTimeField() {
		timer.addObserver(this);
		update(timer);
	}

	public void update(Observable observable) {
		synchronized (UiApplication.getEventLock()) {
			setText(((FlashTimer) observable).getRemainingTime());
		}
	}

}

class FlashOnOffField extends AbstractLabelField implements Observer {
	SimpleOption simpleOption = SimpleOption.getIns();

	public FlashOnOffField() {
		setFont(Constant.FONT_FLASH_ONOFF_FILED);
		simpleOption.addObserver(this);
		update(simpleOption);
	}

	public void update(Observable observable) {
		synchronized (UiApplication.getEventLock()) {
			setText();
		}
	}

	private void setText() {
		if(isCurrentFlashOn()){
			setText("켜짐");
		} else {
			setText("꺼짐");
		}
	}
	
	private boolean isCurrentFlashOn(){
		return simpleOption.isCurrentFlashOn();
	}
	
}

class FlashOnOffButton extends ButtonField implements Observer{
	static private SimpleOption simpleOption = SimpleOption.getIns();
	
	public FlashOnOffButton() {
		super(getButtonName());
		simpleOption.addObserver(this);
		update(simpleOption);
	}
	
	public void update(Observable observable) {
		synchronized (UiApplication.getEventLock()) {
			setLabel(getButtonName());
		}
	}
	
	public static String getButtonName(){
		if (simpleOption.isCurrentFlashOn()) {
			return "손전등 끄기";
		} else {
			return "손전등 켜기";
		}
	}
	
	public int getPreferredHeight() {
		return 70;
	}
	
	public int getPreferredWidth() {
		return Display.getWidth()/2;
	}
}


class TempEditField extends EditField{

	public TempEditField() {
		super();
		// TODO Auto-generated constructor stub
	}

	public TempEditField(long l) {
		super(l);
		// TODO Auto-generated constructor stub
	}

	public TempEditField(String s, String s1, int i, long l) {
		super(s, s1, i, l);
		// TODO Auto-generated constructor stub
	}

	public TempEditField(String s, String s1) {
		super(s, s1);
		// TODO Auto-generated constructor stub
	}

	protected void displayFieldFullMessage() {
	}
}
